package fem2d;

import java.util.ArrayList;

import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Debugger;
import fem2.Element;
import fem2.Force;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.StringUtilities;
import fem2.analysis.Analysis;
import fem2.analysis.LinearBucklingAnalysis;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.material.StVenantKirchhoffMM;
import fem2.observer.GidBucklingModeObserver;
import fem2.observer.TimeStepObserver;
import fem2.observer.TimingObserver;
import fem2.pre_and_post.GidPostStructural;
import fem2.pre_and_post.PatchMeshGenerator;
import fem2.strategies.BucklingStrategy;
import fem2.strategies.Strategy;

public class ColumnBuckling extends AbstractStructuralStaticDemo {

	public ColumnBuckling() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "column_buckling.gid";
		meshFileName = "mesh1";
	}

	@Override
	public Mesh createMesh() {
		int nc = 6;
		int nr = 101;
		double x0 = 0.0;
		double y0 = 0.0;
		double dx = 0.1;
		double dy = 0.5;
		MeshGenerator mg = new PatchMeshGenerator(nc, nr, x0, y0, dx, dy);
		return mg.getMesh(2);
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();

		Constraint c = new Constraint(false, false);
		ArrayList<Node> bottom = MeshUtilities.seekNodesOnSurface(mesh, 0.0, 1.0, 0.0);
		mesh.setConstraint(c, bottom);

		ArrayList<Node> top = MeshUtilities.seekNodesOnSurface(mesh, 0.0, 1.0, 50.0);
		for (int i = 0; i < top.size(); i++) {
			Force f = new Force(top.get(i), 0, -1e5);
			m.addLoad(f);
		}

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 2.1e9;
		double nu = 0.3;
		return new StVenantKirchhoffMM(E, nu, 1.0, 0.0, State.PLANE_STRESS);
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		return new StructuralElement(mp, mm);
	}

	@Override
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		if (meshFileName == null) {
			throw new Error("mesh file name was not set");
		}

		/*
		 * clean all previous post files
		 */
		String meshName = StringUtilities.getFileName(meshFileName);

		GidPostStructural post = new GidPostStructural(projectDir, projectName, meshName);
		post.clearAllPostFiles();

		s.addObserver(new GidBucklingModeObserver(m, null, (BucklingStrategy) s, projectDir,
				projectName, meshName));

		s.addObserver(new TimingObserver());
	}

	@Override
	public void run() {
		Model m = createModel();

		Analysis an = new LinearBucklingAnalysis(m);

		BucklingStrategy s = (BucklingStrategy) an.getStrategy();
		s.setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1);
		s.setNumberOfBucklingModes(5);

		addObservers(m, s, null);

		an.run();

		for (int i = 0; i < 5; i++) {
			s.setCurrentTimeStep(i);
			Debugger.watch("lambda = ", s.getCurrentEigenMode());
			double[] u = s.getCurrentUHat();
			Debugger.watch("u = ", u);
		}

		Debugger.warn("Analysis completed");
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new ColumnBuckling();
		demo.run();
	}
}
